// 创建贪吃蛇构造函数
var Snake = function () {
    this.start = document.querySelector(".btn-start"); // 获取开始游戏的按钮
    this.pause = document.querySelector(".btn-pause"); // 获取暂停游戏的按钮
    this.restart = document.querySelector(".btn-restart"); // 获取重新开始的按钮
    this.modeSelect = document.querySelectorAll(".df-btn button"); // 获取难度按钮容器
    this.moreSetting = document.querySelector(".ct-title span"); // 获取更多设置按钮
    this.lessSetting = document.querySelector(".hidden button"); // 获取关闭设置按钮
    this.borderSelect = document.querySelectorAll(".ct-mode button"); // 获取边界控制按钮容器
    this.gameOptions = document.querySelectorAll(".ct-game input"); // 获取游戏设置容器
    this.confirm = document.getElementById("confirm"); // 获取确定按钮
    this.reset = document.getElementById("reset"); // 获取恢复默认值按钮
    this.easyMode = this.modeSelect[0]; // 获取简单模式的按钮
    this.normalMode = this.modeSelect[1]; // 获取一般模式的按钮
    this.hardMode = this.modeSelect[2]; // 获取困难模式的按钮
    this.openBorder = this.borderSelect[1]; // 获取开启边界模式的按钮
    this.closeBorder = this.borderSelect[0]; // 获取关闭边界模式的按钮
    this.lengthCtrl = this.gameOptions[0]; // 获取长度设置
    this.speedCtrl = this.gameOptions[1]; // 获取移速设置
    this.scoreCtrl = this.gameOptions[2]; // 获取加分设置

    this.map = document.querySelector(".tt-map"); // 获取地图
    this.score = document.querySelector(".score span"); // 获取分数
    this.isBorder = localStorage.getItem("isBorder") === "true" || false; // 边界模式
    this.bonus = 10; // 获取分数加值

    this.row = 30; // 设置地图行数
    this.col = 30; // 设置地图列数
    this.space = 20; // 设置地图格子宽高

    this.ulsArr = []; // 建立记录坐标的二维数组
    this.snakeArr = []; // 建立记录蛇的数组

    this.foodX = 0; // 记录食物的X坐标
    this.foodY = 0; // 记录食物的Y坐标

    this.x = Number(localStorage.getItem("position")) || 5; // 记录蛇头的X坐标
    this.y = 5; // 记录蛇头的Y坐标

    this.direction = "right"; // 记录蛇移动的方向

    this.count = 0; // 记录分数的数值

    this.delay = null; // 设置延时函数
    this.timer = null; // 设置定时器
    this.speed = Number(localStorage.getItem("speed")) || 150; // 设置移动速度
}

// 创建地图
Snake.prototype.createMap = function () {
    // 设置地图参数
    this.row = this.row > 30 ? 30 : this.row;
    this.col = this.col > 30 ? 30 : this.col;
    this.space = this.space > 30 ? 30 : this.space;

    for (var i = 0; i < this.row; i++) {
        var uls = document.createElement("ul");
        uls.style["height"] = this.space + "px";
        this.map.appendChild(uls); // 添加行
        var lisArr = []; // 建立记录坐标的小数组
        for (var j = 0; j < this.col; j++) {
            var lis = document.createElement("li");
            lis.style["width"] = this.space + "px";
            lis.style["height"] = this.space + "px";
            uls.appendChild(lis); // 添加列
            lisArr.push(lis); // 将li标签添加到小数组
        }
        this.ulsArr.push(lisArr); // 将小数组添加到大数组
    }
    
    // 创建地图后存储默认设置
    localStorage.setItem("position", this.x)
    localStorage.setItem("speed", this.speed)
    localStorage.setItem("isBorder", this.isBorder)

    switch (localStorage.getItem("mode")) {
        case "easy":
            this.modeSelect[0].style.borderColor = "lightgreen";
            break;
        case "normal":
            this.modeSelect[1].style.borderColor = "deepskyblue";
            break;
        case "hard":
            this.modeSelect[2].style.borderColor = "red";
            break;
        default:
            break;
    }
    // console.log(this.ulsArr);
}

// 创建蛇
Snake.prototype.createSnake = function () {
    this.snakeArr = [];
    for (var i = 0; i < this.x+1; i++) {
        this.ulsArr[this.y][i].className = "theSnake"; // 将li标签设置蛇身的类名
        this.snakeArr.push(this.ulsArr[this.y][i]); // 将li标签添加到蛇的数组
    }
    this.ulsArr[this.y][this.x].className = "theSnakeHead"; // 设置蛇头的类名
    // console.log(this.snakeArr);
}

// 创建随机数
Snake.prototype.myRandom = function (min, max) {
    return Math.floor(Math.random() * (max - min) + min);
}

// 创建食物
Snake.prototype.createFood = function () {
    // 随机设置食物的位置
    this.foodX = this.myRandom(0, this.col);
    this.foodY = this.myRandom(0, this.row);

    // 手动设置食物的位置
    // this.foodX = 5;
    // this.foodY = 0;

    for (var i = 0; i < this.snakeArr.length; i++) {
        if (this.ulsArr[this.foodY][this.foodX] == this.snakeArr[i]) { // 如果食物生成在蛇身上将重新生成新的食物
            this.createFood();
        } else {
            this.ulsArr[this.foodY][this.foodX].className = "food"; // 将生成的食物设置类名
        }
    }
}

// 处理蛇移动的逻辑
Snake.prototype.snakeMove = function () {
    // 判断蛇移动的方向
    if (this.direction == "right") {
        this.x++;
    } else if (this.direction == "left") {
        this.x--;
    } else if (this.direction == "bottom") {
        this.y++;
    } else if (this.direction == "top") {
        this.y--;
    }

    // 边界处理
    if (this.isBorder) {
        // 处理蛇与地图边界的碰撞
        if (this.x < 0 || this.x > (this.col - 1)) {
            this.myAlert("你刚刚把自己撞傻了！", "哎哟你干嘛~")
            clearInterval(this.timer);
            return;
        }
        if (this.y < 0 || this.y > (this.row - 1)) {
            this.myAlert("你刚刚把自己撞傻了！", "哎哟你干嘛~")
            clearInterval(this.timer);
            return;
        }
    } else {
        // 无碰撞模式
        if (this.x < 0) {
            this.x = (this.col - 1);
        }
        if (this.x > (this.col - 1)) {
            this.x = 0;
        }
        if (this.y < 0) {
            this.y = (this.row - 1);
        }
        if (this.y > (this.row - 1)) {
            this.y = 0;
        }
    }

    var gps = this.ulsArr[this.y][this.x]; // 记录蛇头当前的位置
    var foodGps = this.ulsArr[this.foodY][this.foodX]; // 记录食物当前的位置

    // 处理蛇与自身或食物的碰撞
    for (var i = 1; i < this.snakeArr.length; i++) {
        this.snakeArr[i].className = "theSnake"; // 默认将蛇数组的每一个li标签设置蛇身的类名
        if (gps == this.snakeArr[i]) { // 如果蛇头处于蛇身位置，将结束游戏
            clearInterval(this.timer);
            this.myAlert("你吃掉了自己的脑子！", "哎哟你干嘛~");
            return;
        }
    }
    if (gps == foodGps) { // 蛇移动到食物的位置
        // 将食物位置的li标签添加到蛇数组，并且将当前li标签设置蛇头的类名
        gps.className = "theSnakeHead";
        this.snakeArr.push(gps);
        // 分数自加，渲染到记录分数的标签里
        this.count += this.bonus;
        this.score.innerText = this.count;
        // 重新创建食物
        this.createFood();
    } else { // 蛇没有移动到食物的位置
        gps.className = "theSnakeHead"; // 将当前位置的li标签设置蛇头的类名
        if (gps == this.snakeArr[0]) {
            this.snakeArr[0].className = "theSnakeHead"; // 如果蛇头处在设为位置，设置蛇尾为蛇头的类名
        } else {
            this.snakeArr[0].className = ""; // 移除蛇尾的蛇身类名
        }
        this.snakeArr.push(gps); // 将前进位置的li标签添加到蛇数组，
        this.snakeArr.shift(); // 删除蛇数组末尾的li标签
    }
}

// 游玩
Snake.prototype.handlePlay = function () { // 作用域1
    var that = this;
    this.start.onclick = function () { // 作用域2
        that.snakeMove();
        that.autoPlay();
    }
    this.pause.onclick = function () { // 作用域3
        clearInterval(that.timer);
    }
    this.restart.onclick = function () {
        that.handleReset();
    }
}

// 重置游戏
Snake.prototype.handleReset = function (flag, position, speed) {
    clearInterval(this.timer);

    this.y = 5;
    this.x = position || Number(localStorage.getItem("position"));
    this.speed = speed || Number(localStorage.getItem("speed"));
    this.isBorder = flag !== undefined ? flag : localStorage.getItem("isBorder") === "true";
    this.direction = "right";
    this.count = 0;
    this.score.innerText = this.count;

    this.snakeArr.forEach(function(item) {
        item.className = "";
    });

    this.createSnake();
}

// 参数设置
Snake.prototype.options = function () {
    var that = this;
    var customFlag;
    var customLength;
    var customVelocity;

    // 预设难度设置
    var difficuteChange = function (flag, position, speed) {
        // 修改设置并缓存
        localStorage.setItem("isBorder", flag)
        position && localStorage.setItem("position", position)
        speed && localStorage.setItem("speed", speed)

        that.modeSelect.forEach(function(item) {
            item.style.borderColor = "#ccc";
        });

        that.handleReset(flag, position, speed);
    }

    // 自定义设置
    var customSetting = function (flag, length, velocity) {
        localStorage.setItem("isBorder", flag)
        length && localStorage.setItem("position", length)
        velocity && localStorage.setItem("speed", velocity)

        var isBorder = flag !== undefined ? flag : localStorage.getItem("isBorder") === "true";
        var position = length || Number(localStorage.getItem("position"));
        var speed = velocity || Number(localStorage.getItem("speed"));

        that.borderSelect.forEach(function(item) {
            item.style.borderColor = "#ccc";
        });

        customFlag = isBorder;
        customLength = position;
        customVelocity = speed;
    }

    this.easyMode.onclick = function () { // 简单模式
        difficuteChange(false, 5, 150);
        that.modeSelect[0].style.borderColor = "lightgreen";
        localStorage.setItem("mode", "easy")
    }
    this.normalMode.onclick = function () { // 一般模式
        difficuteChange(true, 15, 100);
        that.modeSelect[1].style.borderColor = "deepskyblue";
        localStorage.setItem("mode", "normal")
    }
    this.hardMode.onclick = function () { // 困难模式
        difficuteChange(true, 28, 20);
        that.modeSelect[2].style.borderColor = "red";
        localStorage.setItem("mode", "hard")
    }

    this.moreSetting.onclick = function () { // 更多设置
        document.querySelector(".op-content ul ol").style.display = "block";
        document.querySelector(".op-content ul ol").style.animation = "slideDown 0.5s ease-in-out";
    }
    this.lessSetting.onclick = function () { // 更少设置
        document.querySelector(".op-content ul ol").style.display = "none";
    }

    this.openBorder.onclick = function () { // 开启边界
        customSetting(true);
        that.borderSelect[1].style.borderColor = "orange";
    }
    this.closeBorder.onclick = function () { // 关闭边界
        customSetting(false);
        that.borderSelect[0].style.borderColor = "lightgreen";
    }

    this.lengthCtrl.oninput = function (event) { // 控制蛇初始长度
        customSetting(undefined, Number(event.target.value));
    }
    this.speedCtrl.oninput = function (event) { // 控制蛇移速
        customSetting(undefined, undefined, Number(event.target.value));
    }
    this.scoreCtrl.oninput = function (event) { // 控制加分值
        that.bonus = Number(event.target.value);
        that.handleReset();
    }
    
    this.confirm.onclick = function () { // 保存自定义设置
        that.easyMode.style.borderColor = "#ccc";
        that.normalMode.style.borderColor = "#ccc";
        that.hardMode.style.borderColor = "#ccc";
        localStorage.removeItem("mode")

        that.handleReset(customFlag, customLength, customVelocity);
        that.myAlert("改好啦", "好得不行", false)
    }
    this.reset.onclick = function () { // 恢复默认值
        difficuteChange(false, 5, 150);
        that.myAlert("改好啦", "好得不行", false)
    }
}

// 提示弹窗
Snake.prototype.myAlert = function (message, btn, flag = true) {
    var that = this;
    var mask = document.createElement("div");
    mask.className = "mask";
    
    var str = '';
    str += '    <div class="content">';
    str += '        <p><span>'+message+'</span> </p>';
    str += '        <div>';
    str += '            <button>'+btn+'</button>';
    str += '        </div>';
    str += '    </div>';

    mask.innerHTML = str;
    document.body.appendChild(mask);

    mask.onclick = function (event) {
        var btnSure = event.target;
        if (btnSure.localName = "button") {
            document.body.removeChild(mask);
            flag && that.handleReset();
        }
    }
}


// 绑定键盘事件
Snake.prototype.keyEvent = function () { // 作用域1
    var that = this;
    document.onkeydown = function (event) { // 作用域2
        var keyCode = event.keyCode;
        // console.log(keyCode);
        // 如果有值，清除延时函数
        if (that.delay) {
            return;
        }
        // 键盘事件进行时，将无法进行反方向的键盘事件
        if (that.direction == "right" && keyCode == 65) {
            return;
        }
        if (that.direction == "left" && keyCode == 68) {
            return;
        }
        if (that.direction == "bottom" && keyCode == 87) {
            return;
        }
        if (that.direction == "top" && keyCode == 83) {
            return;
        }
        // 键盘事件改变方向值
        switch (keyCode) {
            case 68:
                that.direction = "right";
                break;
            case 65:
                that.direction = "left";
                break;
            case 83:
                that.direction = "bottom";
                break;
            case 87:
                that.direction = "top";
                break;
        }
        // that.snakeMove(); // 手动键盘操控
        // 防抖延时函数
        that.delay = setTimeout(function(){
            clearTimeout(that.delay);
            that.delay = null;
        }, 100)
    }
}

// 设置定时器让蛇自动运动
Snake.prototype.autoPlay = function () {
    if (this.timer) clearInterval(this.timer); // 如果有值，清除定时器
    var that = this;
    this.timer = setInterval(function () {
        that.snakeMove();
    }, this.speed)
}

// 初始化
Snake.prototype.init = function () {
    this.createMap();
    this.createSnake();
    this.myRandom();
    this.createFood();
    this.handlePlay();
    this.options();
    this.keyEvent();
}